/* -------------------------------------------------------------------------
 *
 * postgres_fdw.h
 * 		  Foreign-data wrapper for remote PostgreSQL servers
 *
 * Portions Copyright (c) 2020 Huawei Technologies Co.,Ltd.
 * Portions Copyright (c) 2012-2014, PostgreSQL Global Development Group
 *
 * IDENTIFICATION
 * 		  contrib/postgres_fdw/postgres_fdw.h
 *
 * -------------------------------------------------------------------------
 */
#ifndef POSTGRES_FDW_H
#define POSTGRES_FDW_H

#include "foreign/foreign.h"
#include "lib/stringinfo.h"
#include "nodes/relation.h"
#include "utils/rel.h"
#include "libpq/libpq-fe.h"

#include "nodes/execnodes.h"
#include "utils/relcache.h"

/*
 * FDW-specific planner information kept in RelOptInfo.fdw_private for a
 * postgres_fdw foreign table.  For a baserel, this struct is created by
 * postgresGetForeignRelSize, although some fields are not filled till later.
 * postgresGetForeignJoinPaths creates it for a joinrel, and
 * postgresGetForeignUpperPaths creates it for an upperrel.
 */
typedef struct PgFdwRelationInfo {
    /*
     * True means that the relation can be pushed down. Always true for simple
     * foreign scan.
     */
    bool pushdown_safe;

    /*
     * Restriction clauses, divided into safe and unsafe to pushdown subsets.
     * All entries in these lists should have RestrictInfo wrappers; that
     * improves efficiency of selectivity and cost estimation.
     */
    List *remote_conds;
    List *local_conds;

    /* Actual remote restriction clauses for scan (sans RestrictInfos) */
    List *final_remote_exprs;

    /* Bitmap of attr numbers we need to fetch from the remote server. */
    Bitmapset *attrs_used;

    /* True means that the query_pathkeys is safe to push down */
    bool qp_is_pushdown_safe;

    /* Cost and selectivity of local_conds. */
    QualCost local_conds_cost;
    Selectivity local_conds_sel;

    /* Selectivity of join conditions */
    Selectivity joinclause_sel;

    /* Estimated size and cost for a scan with baserestrictinfo quals. */
    double rows;
    int width;
    Cost startup_cost;
    Cost total_cost;

    /*
     * Estimated number of rows fetched from the foreign server, and costs
     * excluding costs for transferring those rows from the foreign server.
     * These are only used by estimate_path_cost_size().
     */
    double retrieved_rows;
    Cost rel_startup_cost;
    Cost rel_total_cost;

    /* Options extracted from catalogs. */
    bool use_remote_estimate;
    Cost fdw_startup_cost;
    Cost fdw_tuple_cost;
    List *shippable_extensions; /* OIDs of shippable extensions */
    bool async_capable;

    /* Cached catalog information. */
    ForeignTable *table;
    ForeignServer *server;
    UserMapping *user; /* only set in use_remote_estimate mode */

    int fetch_size; /* fetch size for this remote table */

    /*
     * Name of the relation, for use while EXPLAINing ForeignScan.  It is used
     * for join and upper relations but is set for all relations.  For a base
     * relation, this is really just the RT index as a string; we convert that
     * while producing EXPLAIN output.  For join and upper relations, the name
     * indicates which base foreign tables are included and the join type or
     * aggregation type used.
     */
    char *relation_name;

    /* Join information */
    RelOptInfo *outerrel;
    RelOptInfo *innerrel;
    JoinType jointype;
    /* joinclauses contains only JOIN/ON conditions for an outer join */
    List *joinclauses; /* List of RestrictInfo */

    /* Upper relation information */
    UpperRelationKind stage;

    /* Grouping information */
    List *grouped_tlist;

    /* Subquery information */
    bool make_outerrel_subquery; /* do we deparse outerrel as a subquery? */
    bool make_innerrel_subquery; /* do we deparse innerrel as a subquery? */
    Relids lower_subquery_rels;  /* all relids appearing in lower subqueries */

    /*
     * Index of the relation.  It is used to create an alias to a subquery
     * representing the relation.
     */
    int relation_index;

    /* target entry list from  */
    List* complete_tlist;
} PgFdwRelationInfo;

/* in postgres_fdw.c */
extern int set_transmission_modes(void);
extern void reset_transmission_modes(int nestlevel);

/* in connection.c */
extern PGconn *GetConnection(ForeignServer *server, UserMapping *user, bool will_prep_stmt);
PGconn* GetConnectionByFScanState(ForeignScanState *node, bool will_prep_stmt);
extern void ReleaseConnection(PGconn *conn);
extern unsigned int GetCursorNumber(PGconn *conn);
extern unsigned int GetPrepStmtNumber(PGconn *conn);
extern PGresult *pgfdw_get_result(PGconn *conn, const char *query);
extern PGresult *pgfdw_exec_query(PGconn *conn, const char *query);
extern void pgfdw_report_error(int elevel, PGresult *res, PGconn *conn, bool clear, const char *sql);

/* in option.c */
extern int ExtractConnectionOptions(List *defelems, const char **keywords, const char **values);

/* in deparse.c */
extern void classifyConditions(PlannerInfo *root, RelOptInfo *baserel, List *input_conds, List **remote_conds,
    List **local_conds);
extern bool is_foreign_expr(PlannerInfo *root, RelOptInfo *baserel, Expr *expr);
extern bool is_foreign_pathkey(PlannerInfo *root, RelOptInfo *baserel, PathKey *pathkey);
extern void deparseInsertSql(StringInfo buf, RangeTblEntry *rte, Index rtindex, Relation rel, List *targetAttrs,
    List *withCheckOptionList, List *returningList, List **retrieved_attrs);
extern void deparseUpdateSql(StringInfo buf, RangeTblEntry *rte, Index rtindex, Relation rel, List *targetAttrs,
    List *withCheckOptionList, List *returningList, List **retrieved_attrs);
extern void deparseDeleteSql(StringInfo buf, RangeTblEntry *rte, Index rtindex, Relation rel, List *returningList,
    List **retrieved_attrs);
extern void deparseAnalyzeSizeSql(StringInfo buf, Relation rel);
extern void deparseAnalyzeSql(StringInfo buf, Relation rel, List **retrieved_attrs);
extern void deparseSelectStmtForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *foreignrel, List *tlist,
    List *remote_conds, List *pathkeys, bool has_final_sort, bool has_limit, bool is_subquery, List **retrieved_attrs,
    List **params_list);

extern const char *get_jointype_name(JoinType jointype);
extern List *build_tlist_to_deparse(RelOptInfo *foreignrel);
extern bool is_foreign_param(PlannerInfo *root, RelOptInfo *baserel, Expr *expr);
extern EquivalenceMember *find_em_for_rel(PlannerInfo *root, EquivalenceClass *ec, RelOptInfo *rel);
extern EquivalenceMember *find_em_for_rel_target(PlannerInfo *root, EquivalenceClass *ec, RelOptInfo *rel);

extern bool is_builtin(Oid oid);

#endif /* POSTGRES_FDW_H */

